package persistencia;

import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;

import logica.util.Data;


/**
 * O gerador de logs eh resposavel por gereciar, criar e excluir arquivos de logs do sistema.
 * O funcionamento eh o seguinte: a medida que o sistema vai precisando vao sendo criados os arquivos,
 * quando o tamanho desse arquivo excede os 1MB o gerador de logs cria outro arquivo ate chegar em um grupo 
 * de cinco arquivos, quando isso acontecer eh gerado um arquivo compactado com todos os cinco arquivos e o ciclo reinicia.
 * @author Equipe Localisa, usa quem precisa
 *
 */
public class GeradorDeLogs {
	
		
	private File arquivoAtual;
	Compactador compactador = new Compactador();
	private final int  TAMANHO_DE_CADA_LOG = 10000;
	private final byte FIM_DE_LINHA = '\n';
	private final String[] nomeDeArquivosDeLog = 
									{"arquivos/logs/log0", "arquivos/logs/log1", "arquivos/logs/log2",
									 "arquivos/logs/log3", "arquivos/logs/log4"};
	/**
	 * Construtor sem paramentros ja faz a verificacao de qual eh o arquivo que esta sendo usado no
	 * momento para armazenar os logs do sistema
	 * @throws IOException
	 */
	public GeradorDeLogs() throws IOException{
	
		File arquivoFlutuante;
		
		for(int i = 0; i <= 4;i++){
			arquivoFlutuante = new File("arquivos/logs/log"+i);
			if(arquivoFlutuante.exists()){
				arquivoAtual = arquivoFlutuante;
			}
		}
		
		if(arquivoAtual == null){
			File arquivoLog0 = new File("arquivos/logs/log0");
			arquivoLog0.createNewFile();
			this.arquivoAtual = arquivoLog0;
		}
		
	}
	
	@SuppressWarnings("deprecation")
	
	
	/**
	 * Escreve uma mensagem no arquivo de log.
	 * @param mensagem - Uma string que sera colocada junto com data e hora no arquivo de log.
	 * @throws Exception
	 */
	
	public void escreveLog(String mensagem) throws Exception{
		
		Calendar calendario = Calendar.getInstance();
		
		Data data = new Data();
		
		String dataHora = String.format("[ %02d/%02d/%04d %02d:%02d:%02d ] ", data.getDia(), data.getMes().getNumero(), data.getAno(), calendario.getTime().getHours(), calendario.getTime().getMinutes(), calendario.getTime().getSeconds());
		
		String log = dataHora+mensagem+"\n";
		
		FileOutputStream saidaParaArquivo = null;
		
		if(this.arquivoAtual.length() <= TAMANHO_DE_CADA_LOG){
			
			String coisasJaEscritas = coisaEscrita(this.arquivoAtual.getPath());
			coisasJaEscritas += log;
			saidaParaArquivo = new FileOutputStream(this.arquivoAtual);
			saidaParaArquivo.write(coisasJaEscritas.getBytes());
						
		}
		else{
			
			if(arquivoAtual.getName().equals("log4")){
				//Gera o arquivo compactado com todos os arquivos
				compactador.geraArquivoZipado("arquivos/logs/"+data.getDia()+"-"+data.getMes().getNumero()+"-"+data.getAno()+"-"+
											  calendario.getTime().getHours()+"-"+calendario.getTime().getMinutes()+"-"+
											  calendario.getTime().getSeconds(), this.nomeDeArquivosDeLog);
				//Apaga todos os arquivos antigos
				File arquivoASerApagado; 
				for(int i=0; i<=4;i++){
					arquivoASerApagado = new File("arquivos/logs/log"+i);
					arquivoASerApagado.delete();
				}
				//Cria o arquivo log0 novamente
				File arquivoLog0 = new File("arquivos/logs/log0");
				arquivoLog0.createNewFile();
				this.arquivoAtual = arquivoLog0;
				String coisasJaEscritas = coisaEscrita(this.arquivoAtual.getPath());
				coisasJaEscritas += log;
				saidaParaArquivo = new FileOutputStream(this.arquivoAtual);
				saidaParaArquivo.write(coisasJaEscritas.getBytes());
				
			
			}else if(!arquivoAtual.getName().equals("log4")){
			
				int numeroDoNome = Integer.parseInt(Character.toString(this.arquivoAtual.getName().charAt(3)));
				File arquivoNovo = new File("arquivos/logs/log"+(numeroDoNome + 1));
				this.arquivoAtual = arquivoNovo;
				saidaParaArquivo = new FileOutputStream(this.arquivoAtual);
				saidaParaArquivo.write(log.getBytes());
				
			}
			
			saidaParaArquivo.close();
			
		}//Fim do metodo escreveLog
		
			
		
	}
	
	/*Esse metodo serve para recuperar o que ja existe no arquivo antes de adicionar algo novo*/
	private String coisaEscrita(String arquivo) throws Exception{
		
				
		String stringSaida = "";
		
		FileInputStream streamArquivo = new FileInputStream(arquivo);
		
		int caracter;
				
		try{
			
			while((caracter = streamArquivo.read()) != -1 ){
				
				stringSaida += String.valueOf( (char) caracter );
			}
			streamArquivo.close();
			return stringSaida;
		}catch(EOFException e){
			streamArquivo.close();
			return stringSaida;
		}
				
		
	}
	
	/**
	 * Retorna as ultimas acoes do sistema
	 * @param numero - que vai dizer quantas acoes serao retornadas
	 * @return Uma string com as dez ultimas acoes que foram realizadas no sistema
	 * @throws IOException
	 */
	public String ultimasAcoes(int numero) throws Exception{
		
		char caracter;
		int qtdeLinhas = this.contaLinhas(this.arquivoAtual);
		ArrayList<String> resultante = new ArrayList<String>();
		String listaDeLinhas = "";
		FileInputStream entrada = new FileInputStream(this.arquivoAtual);
		try{
			for(int i=0; i<=numero;i++){
				if ( i < qtdeLinhas ){
					String umaLinha="\n \t ";
					while( (caracter = (char) entrada.read()) != this.FIM_DE_LINHA ){
						umaLinha+=caracter;
					}
					resultante.add(umaLinha);					
				}
			}
			entrada.close();
			
			for(int linha = resultante.size() - 1 ; linha > -1; linha--){
				listaDeLinhas += resultante.get(linha);
			}
			
			return listaDeLinhas;
		}catch(EOFException eof){
			entrada.close();
			throw new IOException("\n \t <Esse indice eh maior que a quantidade de logs acessiveis.>");
			
		}
			
	}

	// Conta quantas linhas possui um arquivo
	
	private int contaLinhas(File arquivo) throws Exception{
		FileInputStream entrada = new FileInputStream(arquivo);
		try{
			int qtde = 0;
			int ponteiro = 0;
			while ( (ponteiro = entrada.read()) != -1 ){
				if ( (char) ponteiro == this.FIM_DE_LINHA ){
					qtde++;
				}
			}
			entrada.close();
			return qtde;
		}
		catch( EOFException eof ){
			entrada.close();
			throw new IOException("\n \t <Erro ao contar a qtde de linhas de arquivo.>");
		}
	}
	
}